package com.prototype.deepclone;

import java.io.*;

/**
 * 源对象，通过这个对象，克隆出多个对象
 * 实现Cloneable接口，主要为了通过clone的方式实现深拷贝
 * 实现Seriable接口，主要为了通过 序列化的方式实现深拷贝
 */
public class DeepPrototype implements Serializable,Cloneable {

    private String name ;

    private DeepCloneTarget deepCloneTarget;

    public DeepPrototype(){}

    public DeepPrototype(String name, DeepCloneTarget deepCloneTarget) {
        this.name = name;
        this.deepCloneTarget = deepCloneTarget;
    }

    //todo:方法一：通过重写clone方法，对基本类型，引用类型属性单独处理实现深拷贝
    //重写clone方法实现以深拷贝的方式 , ** 注意需要对引用类型的属性进行单独处理
    @Override
    protected Object clone(){
        DeepPrototype deepPrototype = null ;
        try {
            //调用父类的clone方法，此时基本类型相当于进行了深拷贝，但是引用类型，仅仅是复制了地址值
            deepPrototype = (DeepPrototype) super.clone();
            //单独对DeepPrototype的deepCloneTarget属性进行处理，实现深拷贝
            deepPrototype.deepCloneTarget =(DeepCloneTarget) deepCloneTarget.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return deepPrototype;
    }

    //todo：方法二： 通过序列化的方式，实现对象深拷贝（推荐）
    public Object deepCopyBySerializable(){
        //创建序列化时候使用的流对象
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bis = null ;
        ObjectInputStream ois = null ;
        try {
            //序列化 把当前对象写到流中
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(this);

            //反序列化，将流中的数据反序列化为对象
            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            Object deepType = ois.readObject();
            return deepType ;
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            //关闭流
            try {
                bos.close();
                oos.close();
                bis.close();
                ois.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public DeepCloneTarget getDeepCloneTarget() {
        return deepCloneTarget;
    }

    public void setDeepCloneTarget(DeepCloneTarget deepCloneTarget) {
        this.deepCloneTarget = deepCloneTarget;
    }
}
